Introduction

NOTE: This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

In last few practices/sessions, you learned about spatial point patterns. The next few sessions will concentrate on area data.

For this practice you will need the following:

This dataset includes the spatial information for the census tracts in the Hamilton Census Metropolitan Area (as polygons), and a host of demographic variables from the census of Canada, including population and languages.

Learning objectives

In this practice, you will learn:

  1. A formal definition of area data.
  2. Processes and area data.
  3. Visualizing area data: Choropleth maps.
  4. Visualizing area data: Cartograms.

Suggested reading

O’Sullivan D and Unwin D (2010) Geographic Information Analysis, 2nd Edition, Chapter 7. John Wiley & Sons: New Jersey.

Preliminaries

As usual, it is good practice to clear the working space to make sure that you do not have extraneous items there when you begin your work. The command in R to clear the workspace is rm (for “remove”), followed by a list of items to be removed. To clear the workspace from all objects, do the following:

rm(list = ls())

Note that ls() lists all objects currently on the worspace.

Load the libraries you will use in this activity:

library(tidyverse)
package <U+393C><U+3E31>tidyverse<U+393C><U+3E32> was built under R version 3.4.3-- Attaching packages --------------------------------------------- tidyverse 1.2.1 --
v ggplot2 2.2.1     v purrr   0.2.4
v tibble  1.4.1     v dplyr   0.7.4
v tidyr   0.7.2     v stringr 1.2.0
v readr   1.1.1     v forcats 0.2.0
package <U+393C><U+3E31>ggplot2<U+393C><U+3E32> was built under R version 3.4.2package <U+393C><U+3E31>tibble<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>tidyr<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>purrr<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>dplyr<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>forcats<U+393C><U+3E32> was built under R version 3.4.3-- Conflicts ------------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(rgdal)
Loading required package: sp
rgdal: version: 1.2-11, (SVN revision 676)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.2.0, released 2017/04/28
 Path to GDAL shared files: C:/Users/Antonio/Documents/R/win-library/3.4/rgdal/gdal
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: C:/Users/Antonio/Documents/R/win-library/3.4/rgdal/proj
 Linking to sp version: 1.2-5 
library(broom)
library(plotly)
package <U+393C><U+3E31>plotly<U+393C><U+3E32> was built under R version 3.4.3
Attaching package: <U+393C><U+3E31>plotly<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:ggplot2<U+393C><U+3E32>:

    last_plot

The following object is masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:

    filter

The following object is masked from <U+393C><U+3E31>package:graphics<U+393C><U+3E32>:

    layout
library(cartogram)
package <U+393C><U+3E31>cartogram<U+393C><U+3E32> was built under R version 3.4.3
library(gridExtra)
package <U+393C><U+3E31>gridExtra<U+393C><U+3E32> was built under R version 3.4.3
Attaching package: <U+393C><U+3E31>gridExtra<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:dplyr<U+393C><U+3E32>:

    combine

Read the data that you will use for this practice. This is an Esri shape file that will be saved as an object of class SpatialPolygonDataFrame. The function used to read Esri shape files is rgdal::readOGR. Setting integer64 to “allow.loss” keeps the data as integers as opposed to changing to factors or strings:

Hamilton_CT <- readOGR(".", layer = "Hamilton CMA CT", integer64 = "allow.loss")
OGR data source with driver: ESRI Shapefile 
Source: ".", layer: "Hamilton CMA CT"
with 188 features
It has 255 fields
Integer64 fields read as signed 32-bit integers:  ID POPULATION PRIVATE_DW OCCUPIED_D ALL_AGES AGE_4 AGE_5_TO_9 AGE_10_TO_ AGE_15_TO_ AGE_15 AGE_16 AGE_17 AGE_18 AGE_19 AGE_20_TO_ AGE_25_TO_ AGE_30_TO_ AGE_35_TO_ AGE_40_TO_ AGE_45_TO_ AGE_50_TO_ AGE_55_TO_ AGE_60_TO_ AGE_65_TO_ AGE_70_TO_ AGE_75_TO_ AGE_80_TO_ AGE_85 MEDIAN_AGE MALE_ALL_A MALE_4 MALE_5_TO_ MALE_10_TO MALE_15_TO MALE_15 MALE_16 MALE_17 MALE_18 MALE_19 MALE_20_TO MALE_25_TO MALE_30_TO MALE_35_TO MALE_40_TO MALE_45_TO MALE_50_TO MALE_55_TO MALE_60_TO MALE_65_TO MALE_70_TO MALE_75_TO MALE_80_TO MALE_85 MALE_MEDIA FEMALE_ALL FEMALE_4 FEMALE_5_T FEMALE_10_ FEMALE_15_ FEMALE_15 FEMALE_16 FEMALE_17 FEMALE_18 FEMALE_19 FEMALE_20_ FEMALE_25_ FEMALE_30_ FEMALE_35_ FEMALE_40_ FEMALE_45_ FEMALE_50_ FEMALE_55_ FEMALE_60_ FEMALE_65_ FEMALE_70_ FEMALE_75_ FEMALE_80_ FEMALE_85 FEMALE_MED MARRIED_AG MARRIED_OR MARRIED COMMON_LAW UNMARRIED SINGLE SEPARATED DIVORCED WIDOWED MARRIED_A1 MARRIED_O1 MARRIED_M COMMON_LA1 UNMARRIED_ SINGLE_M SEPARATED_ DIVORCED_M WIDOWED_M MARRIED_A2 MARRIED_O2 MARRIED_F COMMON_LA2 UNMARRIED1 SINGLE_F SEPARATED1 DIVORCED_F WIDOWED_F FAMILIES_I FAMILY_SIZ FAMILY_SI1 FAMILY_SI2 FAMILY_SI3 COUPLE_FAM COUPLE_MAR COUPLE_MA1 COUPLE_MA2 COUPLE_MA3 COUPLE_MA4 COUPLE_MA5 COUPLE_COM COUPLE_CO1 COUPLE_CO2 COUPLE_CO3 COUPLE_CO4 COUPLE_CO5 SINGLE_PAR SINGLE_PA1 SINGLE_PA2 SINGLE_PA3 SINGLE_PA4 SINGLE_PA5 SINGLE_PA6 SINGLE_PA7 SINGLE_PA8 CHILDREN_F CHILDREN_1 CHILDREN_2 CHILDREN_3 CHILDREN_4 CHILDREN_5 POPULATIO1 POPULATIO2 POPULATIO3 POPULATIO4 POPULATIO5 POPULATIO6 POPULATIO7 POPULATIO8 POPULATIO9 POPULATI10 POPULATI11 POPULATI12 PRIVATE_HO PRIVATE_HH PRIVATE_H1 PRIVATE_H2 PRIVATE_H3 PRIVATE_H4 PRIVATE_H5 PRIVATE_H6 PRIVATE_H7 PRIVATE_H8 PRIVATE_H9 PRIVATE_10 PRIVATE_11 PRIVATE_12 PRIVATE_13 PRIVATE_14 PRIVATE_15 OCC_PRIVAT OCC_PRIVA1 OCC_PRIVA2 OCC_PRIVA3 OCC_PRIVA4 OCC_PRIVA5 OCC_PRIVA6 OCC_PRIVA7 OCC_PRIVA8 OCC_PRIVA9 PRIVATE_16 PRIVATE_17 PRIVATE_18 PRIVATE_19 PRIVATE_20 PRIVATE_21 PRIVATE_22 PRIVATE_23 NATIVE_LAN NATIVE_LA1 NATIVE_LA2 NATIVE_LA3 NATIVE_LA4 NATIVE_LA5 NATIVE_LA6 NATIVE_LA7 NATIVE_LA8 NATIVE_LA9 NATIVE_L10 NATIVE_L11 NATIVE_L12 NATIVE_L13 NATIVE_L14 NATIVE_L15 NATIVE_L16 NATIVE_L17 NATIVE_L18 NATIVE_L19 NATIVE_L20 NATIVE_L21 NATIVE_L22 NATIVE_L23 NATIVE_L24 NATIVE_L25 NATIVE_L26 NATIVE_L27 NATIVE_L28 NATIVE_L29 NATIVE_L30 NATIVE_L31 NATIVE_L32 NATIVE_L33 NATIVE_L34 NATIVE_L35 NATIVE_L36 NATIVE_L37 NATIVE_L38 NATIVE_L39 NATIVE_L40 NATIVE_L41 NATIVE_L42 NATIVE_L43 NATIVE_L44 NATIVE_L45 NATIVE_L46 NATIVE_L47 NATIVE_L48 NATIVE_L49 NATIVE_L50 NATIVE_L51 NATIVE_L52 NATIVE_L53 NATIVE_L54 NATIVE_L55 NATIVE_L56 NATIVE_L57 NATIVE_L58 NATIVE_L59 

To use the plotting functions of ggplot2, the SpatialPolygonDataFrame needs to be “tidied” by means of the tidy function of the broom package:

Hamilton_CT.t <- tidy(Hamilton_CT, region = "TRACT")
Hamilton_CT.t <- dplyr::rename(Hamilton_CT.t, TRACT = id)

Tidying the spatial dataframe strips it from the non-spatial information, but we can add all the data by means of the left_join function:

Hamilton_CT.t <- left_join(Hamilton_CT.t, Hamilton_CT@data, by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector

Now the tidy dataframe Hamilton_DA.t contains the spatial information and the data.

You can quickly verify the contents of the dataframe by means of summary:

summary(Hamilton_CT.t)
      long             lat            order          hole         piece    
 Min.   :-80.25   Min.   :43.05   Min.   :    1   Mode :logical   1:29212  
 1st Qu.:-79.93   1st Qu.:43.21   1st Qu.: 7304   FALSE:29212              
 Median :-79.86   Median :43.24   Median :14606                            
          group          TRACT                 ID               AREA         
 5370124.00.1:  822   Length:29212       Min.   : 919807   Min.   :  0.3154  
 5370121.00.1:  661   Class :character   1st Qu.: 920233   1st Qu.:  1.2217  
 5370142.01.1:  642   Mode  :character   Median : 937830   Median :  2.6824  
    COLORING      CMA        PROVINCE        NAME       ABBREV       POPULATION   
 Min.   :0.000   537:29212   00:14311   0124.00:  822   ON:29212   Min.   :    5  
 1st Qu.:0.000               01: 9506   0121.00:  661              1st Qu.: 2756  
 Median :2.000               02: 4394   0142.01:  642              Median : 3901  
   PRIVATE_DW     OCCUPIED_D     LAND_AREA        POP_DENSIT           ALL_AGES    
 Min.   :   0   Min.   :   0   Min.   :  0.32   Min.   :    2.591   Min.   :    0  
 1st Qu.:1191   1st Qu.:1170   1st Qu.:  1.22   1st Qu.:  254.658   1st Qu.: 2755  
 Median :1526   Median :1436   Median :  2.62   Median : 1511.957   Median : 3905  
     AGE_4          AGE_5_TO_9       AGE_10_TO_      AGE_15_TO_        AGE_15      
 Min.   :   0.0   Min.   :   0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.00  
 1st Qu.: 115.0   1st Qu.: 125.0   1st Qu.:140.0   1st Qu.:170.0   1st Qu.: 30.00  
 Median : 175.0   Median : 195.0   Median :220.0   Median :260.0   Median : 45.00  
     AGE_16           AGE_17           AGE_18           AGE_19         AGE_20_TO_   
 Min.   :  0.00   Min.   :  0.00   Min.   :  0.00   Min.   :  0.00   Min.   :  0.0  
 1st Qu.: 30.00   1st Qu.: 35.00   1st Qu.: 35.00   1st Qu.: 35.00   1st Qu.:180.0  
 Median : 55.00   Median : 50.00   Median : 55.00   Median : 55.00   Median :245.0  
   AGE_25_TO_      AGE_30_TO_       AGE_35_TO_       AGE_40_TO_       AGE_45_TO_ 
 Min.   :  0.0   Min.   :   0.0   Min.   :   0.0   Min.   :   0.0   Min.   :  0  
 1st Qu.:135.0   1st Qu.: 125.0   1st Qu.: 145.0   1st Qu.: 180.0   1st Qu.:215  
 Median :205.0   Median : 185.0   Median : 205.0   Median : 245.0   Median :300  
   AGE_50_TO_      AGE_55_TO_      AGE_60_TO_      AGE_65_TO_      AGE_70_TO_   
 Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0  
 1st Qu.:220.0   1st Qu.:190.0   1st Qu.:160.0   1st Qu.:130.0   1st Qu.: 95.0  
 Median :310.0   Median :300.0   Median :260.0   Median :185.0   Median :140.0  
   AGE_75_TO_      AGE_80_TO_        AGE_85         MEDIAN_AGE      MALE_ALL_A  
 Min.   :  0.0   Min.   :  0.0   Min.   :  0.00   Min.   : 0.00   Min.   :   0  
 1st Qu.: 75.0   1st Qu.: 50.0   1st Qu.: 35.00   1st Qu.:38.00   1st Qu.:1345  
 Median :105.0   Median : 85.0   Median : 75.00   Median :43.00   Median :1925  
     MALE_4        MALE_5_TO_      MALE_10_TO      MALE_15_TO       MALE_15     
 Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   : 0.00  
 1st Qu.: 60.0   1st Qu.: 65.0   1st Qu.: 75.0   1st Qu.: 85.0   1st Qu.:15.00  
 Median : 90.0   Median :100.0   Median :120.0   Median :130.0   Median :25.00  
    MALE_16         MALE_17         MALE_18         MALE_19         MALE_20_TO   
 Min.   : 0.00   Min.   :  0.0   Min.   :  0.0   Min.   :  0.00   Min.   :  0.0  
 1st Qu.:15.00   1st Qu.: 15.0   1st Qu.: 15.0   1st Qu.: 20.00   1st Qu.: 90.0  
 Median :25.00   Median : 25.0   Median : 30.0   Median : 30.00   Median :125.0  
   MALE_25_TO      MALE_30_TO      MALE_35_TO    MALE_40_TO      MALE_45_TO   
 Min.   :  0.0   Min.   :  0.0   Min.   :  0   Min.   :  0.0   Min.   :  0.0  
 1st Qu.: 70.0   1st Qu.: 60.0   1st Qu.: 70   1st Qu.: 90.0   1st Qu.:105.0  
 Median :105.0   Median : 85.0   Median :100   Median :115.0   Median :150.0  
   MALE_50_TO      MALE_55_TO    MALE_60_TO      MALE_65_TO       MALE_70_TO    
 Min.   :  0.0   Min.   :  0   Min.   :  0.0   Min.   :  0.00   Min.   :  0.00  
 1st Qu.:110.0   1st Qu.: 95   1st Qu.: 75.0   1st Qu.: 60.00   1st Qu.: 45.00  
 Median :145.0   Median :140   Median :125.0   Median : 90.00   Median : 65.00  
   MALE_75_TO       MALE_80_TO        MALE_85        MALE_MEDIA      FEMALE_ALL  
 Min.   :  0.00   Min.   :  0.00   Min.   :  0.0   Min.   : 0.00   Min.   :   0  
 1st Qu.: 35.00   1st Qu.: 20.00   1st Qu.: 15.0   1st Qu.:37.00   1st Qu.:1405  
 Median : 50.00   Median : 35.00   Median : 25.0   Median :42.00   Median :1920  
    FEMALE_4       FEMALE_5_T      FEMALE_10_      FEMALE_15_      FEMALE_15    
 Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   : 0.00  
 1st Qu.: 50.0   1st Qu.: 60.0   1st Qu.: 70.0   1st Qu.: 80.0   1st Qu.:15.00  
 Median : 85.0   Median : 90.0   Median :105.0   Median :125.0   Median :25.00  
   FEMALE_16       FEMALE_17       FEMALE_18        FEMALE_19        FEMALE_20_   
 Min.   : 0.00   Min.   :  0.0   Min.   :  0.00   Min.   :  0.00   Min.   :  0.0  
 1st Qu.:15.00   1st Qu.: 15.0   1st Qu.: 15.00   1st Qu.: 15.00   1st Qu.: 80.0  
 Median :25.00   Median : 25.0   Median : 25.00   Median : 25.00   Median :120.0  
   FEMALE_25_      FEMALE_30_      FEMALE_35_      FEMALE_40_      FEMALE_45_   
 Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0  
 1st Qu.: 65.0   1st Qu.: 65.0   1st Qu.: 75.0   1st Qu.: 90.0   1st Qu.:105.0  
 Median :100.0   Median : 95.0   Median :105.0   Median :130.0   Median :155.0  
   FEMALE_50_    FEMALE_55_      FEMALE_60_      FEMALE_65_      FEMALE_70_    
 Min.   :  0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.00  
 1st Qu.:110   1st Qu.: 95.0   1st Qu.: 85.0   1st Qu.: 65.0   1st Qu.: 50.00  
 Median :160   Median :155.0   Median :135.0   Median : 90.0   Median : 70.00  
   FEMALE_75_       FEMALE_80_       FEMALE_85        FEMALE_MED      MARRIED_AG  
 Min.   :  0.00   Min.   :  0.00   Min.   :  0.00   Min.   : 0.00   Min.   :   0  
 1st Qu.: 40.00   1st Qu.: 25.00   1st Qu.: 20.00   1st Qu.:39.00   1st Qu.:2355  
 Median : 60.00   Median : 45.00   Median : 45.00   Median :43.00   Median :3230  
   MARRIED_OR      MARRIED       COMMON_LAW      UNMARRIED        SINGLE      
 Min.   :   0   Min.   :   0   Min.   :  0.0   Min.   :   0   Min.   :   0.0  
 1st Qu.:1250   1st Qu.:1065   1st Qu.:145.0   1st Qu.:1035   1st Qu.: 660.0  
 Median :1995   Median :1715   Median :210.0   Median :1335   Median : 840.0  
   SEPARATED         DIVORCED        WIDOWED        MARRIED_A1     MARRIED_O1  
 Min.   :  0.00   Min.   :  0.0   Min.   :  0.0   Min.   :   0   Min.   :   0  
 1st Qu.: 55.00   1st Qu.:110.0   1st Qu.:120.0   1st Qu.:1145   1st Qu.: 620  
 Median : 85.00   Median :175.0   Median :180.0   Median :1595   Median :1000  
   MARRIED_M        COMMON_LA1      UNMARRIED_        SINGLE_M        SEPARATED_    
 Min.   :   0.0   Min.   :  0.0   Min.   :   0.0   Min.   :   0.0   Min.   :  0.00  
 1st Qu.: 530.0   1st Qu.: 70.0   1st Qu.: 475.0   1st Qu.: 355.0   1st Qu.: 25.00  
 Median : 860.0   Median :105.0   Median : 585.0   Median : 450.0   Median : 35.00  
   DIVORCED_M       WIDOWED_M        MARRIED_A2     MARRIED_O2     MARRIED_F     
 Min.   :  0.00   Min.   :  0.00   Min.   :   0   Min.   :   0   Min.   :   0.0  
 1st Qu.: 45.00   1st Qu.: 25.00   1st Qu.:1225   1st Qu.: 625   1st Qu.: 535.0  
 Median : 60.00   Median : 40.00   Median :1675   Median :1000   Median : 855.0  
   COMMON_LA2      UNMARRIED1        SINGLE_F        SEPARATED1       DIVORCED_F   
 Min.   :  0.0   Min.   :   0.0   Min.   :   0.0   Min.   :  0.00   Min.   :  0.0  
 1st Qu.: 70.0   1st Qu.: 525.0   1st Qu.: 285.0   1st Qu.: 25.00   1st Qu.: 60.0  
 Median :105.0   Median : 680.0   Median : 385.0   Median : 55.00   Median :110.0  
   WIDOWED_F       FAMILIES_I     FAMILY_SIZ       FAMILY_SI1    FAMILY_SI2 
 Min.   :  0.0   Min.   :   0   Min.   :   0.0   Min.   :  0   Min.   :  0  
 1st Qu.: 95.0   1st Qu.: 765   1st Qu.: 385.0   1st Qu.:165   1st Qu.:135  
 Median :140.0   Median :1105   Median : 515.0   Median :235   Median :225  
   FAMILY_SI3      COUPLE_FAM     COUPLE_MAR       COUPLE_MA1       COUPLE_MA2  
 Min.   :  0.0   Min.   :   0   Min.   :   0.0   Min.   :   0.0   Min.   :   0  
 1st Qu.: 60.0   1st Qu.: 605   1st Qu.: 530.0   1st Qu.: 225.0   1st Qu.: 265  
 Median : 90.0   Median : 985   Median : 840.0   Median : 360.0   Median : 430  
   COUPLE_MA3      COUPLE_MA4      COUPLE_MA5      COUPLE_COM      COUPLE_CO1    
 Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.00  
 1st Qu.:105.0   1st Qu.:115.0   1st Qu.: 50.0   1st Qu.: 70.0   1st Qu.: 40.00  
 Median :170.0   Median :185.0   Median : 80.0   Median :105.0   Median : 60.00  
   COUPLE_CO2       COUPLE_CO3      COUPLE_CO4      COUPLE_CO5       SINGLE_PAR   
 Min.   :  0.00   Min.   : 0.00   Min.   : 0.00   Min.   : 0.000   Min.   :  0.0  
 1st Qu.: 25.00   1st Qu.:10.00   1st Qu.:10.00   1st Qu.: 5.000   1st Qu.:105.0  
 Median : 45.00   Median :20.00   Median :15.00   Median : 5.000   Median :165.0  
   SINGLE_PA1    SINGLE_PA2       SINGLE_PA3       SINGLE_PA4       SINGLE_PA5   
 Min.   :  0   Min.   :  0.00   Min.   :  0.00   Min.   :  0.00   Min.   : 0.00  
 1st Qu.: 75   1st Qu.: 45.00   1st Qu.: 20.00   1st Qu.:  5.00   1st Qu.:25.00  
 Median :135   Median : 75.00   Median : 35.00   Median : 15.00   Median :40.00  
   SINGLE_PA6      SINGLE_PA7       SINGLE_PA8       CHILDREN_F     CHILDREN_1  
 Min.   : 0.00   Min.   : 0.000   Min.   : 0.000   Min.   :   0   Min.   :   0  
 1st Qu.:15.00   1st Qu.: 5.000   1st Qu.: 0.000   1st Qu.: 805   1st Qu.: 140  
 Median :25.00   Median :10.000   Median : 5.000   Median :1195   Median : 210  
   CHILDREN_2       CHILDREN_3    CHILDREN_4      CHILDREN_5      POPULATIO1   
 Min.   :   0.0   Min.   :  0   Min.   :  0.0   Min.   :  0.0   Min.   :    0  
 1st Qu.: 240.0   1st Qu.: 95   1st Qu.:180.0   1st Qu.:115.0   1st Qu.: 2755  
 Median : 375.0   Median :140   Median :290.0   Median :160.0   Median : 3865  
   POPULATIO2       POPULATIO3       POPULATIO4       POPULATIO5     POPULATIO6   
 Min.   :   0.0   Min.   :  0.00   Min.   :  0.00   Min.   :   0   Min.   :    0  
 1st Qu.: 295.0   1st Qu.: 50.00   1st Qu.: 50.00   1st Qu.: 170   1st Qu.: 2175  
 Median : 425.0   Median : 70.00   Median : 70.00   Median : 295   Median : 3340  
   POPULATIO7       POPULATIO8      POPULATIO9      POPULATI10       POPULATI11   
 Min.   :   0.0   Min.   :  0.0   Min.   : 0.00   Min.   : 0.000   Min.   :  0.0  
 1st Qu.: 390.0   1st Qu.:105.0   1st Qu.:20.00   1st Qu.: 5.000   1st Qu.: 70.0  
 Median : 545.0   Median :150.0   Median :30.00   Median :10.000   Median :110.0  
   POPULATI12       PRIVATE_HO     PRIVATE_HH     PRIVATE_H1     PRIVATE_H2  
 Min.   :   0.0   Min.   :   0   Min.   :   0   Min.   :   0   Min.   :   0  
 1st Qu.: 260.0   1st Qu.:1170   1st Qu.: 750   1st Qu.: 670   1st Qu.: 550  
 Median : 385.0   Median :1435   Median :1075   Median :1015   Median : 885  
   PRIVATE_H3       PRIVATE_H4       PRIVATE_H5      PRIVATE_H6       PRIVATE_H7    
 Min.   :   0.0   Min.   :   0.0   Min.   :  0.0   Min.   :  0.00   Min.   :  0.00  
 1st Qu.: 260.0   1st Qu.: 275.0   1st Qu.: 80.0   1st Qu.: 55.00   1st Qu.: 40.00  
 Median : 385.0   Median : 435.0   Median :145.0   Median : 90.00   Median : 60.00  
   PRIVATE_H8       PRIVATE_H9      PRIVATE_10       PRIVATE_11      PRIVATE_12    
 Min.   :  0.00   Min.   : 0.00   Min.   :  0.00   Min.   : 0.00   Min.   :  0.00  
 1st Qu.: 25.00   1st Qu.:10.00   1st Qu.: 15.00   1st Qu.:10.00   1st Qu.: 15.00  
 Median : 40.00   Median :15.00   Median : 25.00   Median :15.00   Median : 30.00  
   PRIVATE_13       PRIVATE_14       PRIVATE_15       OCC_PRIVAT     OCC_PRIVA1  
 Min.   :   0.0   Min.   :   0.0   Min.   :  0.00   Min.   :   0   Min.   :   0  
 1st Qu.: 190.0   1st Qu.: 170.0   1st Qu.: 20.00   1st Qu.:1170   1st Qu.: 615  
 Median : 330.0   Median : 300.0   Median : 30.00   Median :1435   Median : 945  
   OCC_PRIVA2       OCC_PRIVA3        OCC_PRIVA4       OCC_PRIVA5    
 Min.   :   0.0   Min.   :  0.000   Min.   :   0.0   Min.   :  0.00  
 1st Qu.:   0.0   1st Qu.:  0.000   1st Qu.: 100.0   1st Qu.:  5.00  
 Median :   0.0   Median :  0.000   Median : 365.0   Median : 15.00  
   OCC_PRIVA6       OCC_PRIVA7       OCC_PRIVA8       OCC_PRIVA9       PRIVATE_16  
 Min.   :   0.0   Min.   :  0.00   Min.   :  0.00   Min.   : 0.000   Min.   :   0  
 1st Qu.:   0.0   1st Qu.: 10.00   1st Qu.:  5.00   1st Qu.: 0.000   1st Qu.:1170  
 Median :  85.0   Median : 20.00   Median : 45.00   Median : 0.000   Median :1435  
   PRIVATE_17       PRIVATE_18       PRIVATE_19      PRIVATE_20      PRIVATE_21   
 Min.   :   0.0   Min.   :   0.0   Min.   :  0.0   Min.   :  0.0   Min.   :  0.0  
 1st Qu.: 175.0   1st Qu.: 380.0   1st Qu.:170.0   1st Qu.:145.0   1st Qu.: 50.0  
 Median : 300.0   Median : 470.0   Median :230.0   Median :225.0   Median : 80.0  
   PRIVATE_22       PRIVATE_23      NATIVE_LAN      NATIVE_LA1      NATIVE_LA2  
 Min.   :  0.00   Min.   :    0   Min.   :    0   Min.   :    0   Min.   :   0  
 1st Qu.: 25.00   1st Qu.: 2755   1st Qu.: 2755   1st Qu.: 2725   1st Qu.:2120  
 Median : 40.00   Median : 3865   Median : 3865   Median : 3840   Median :3035  
   NATIVE_LA3       NATIVE_LA4       NATIVE_LA5       NATIVE_LA6   NATIVE_LA7
 Min.   :  0.00   Min.   :   0.0   Min.   :0.0000   Min.   :0    Min.   :0   
 1st Qu.: 30.00   1st Qu.: 380.0   1st Qu.:0.0000   1st Qu.:0    1st Qu.:0   
 Median : 50.00   Median : 645.0   Median :0.0000   Median :0    Median :0   
   NATIVE_LA8   NATIVE_LA9   NATIVE_L10   NATIVE_L11   NATIVE_L12        NATIVE_L13
 Min.   :0    Min.   :0    Min.   :0    Min.   :0    Min.   :0.00000   Min.   :0   
 1st Qu.:0    1st Qu.:0    1st Qu.:0    1st Qu.:0    1st Qu.:0.00000   1st Qu.:0   
 Median :0    Median :0    Median :0    Median :0    Median :0.00000   Median :0   
   NATIVE_L14   NATIVE_L15       NATIVE_L16        NATIVE_L17       NATIVE_L18    
 Min.   :0    Min.   :   0.0   Min.   : 0.0000   Min.   : 0.000   Min.   : 0.000  
 1st Qu.:0    1st Qu.: 375.0   1st Qu.: 0.0000   1st Qu.: 0.000   1st Qu.: 0.000  
 Median :0    Median : 635.0   Median : 0.0000   Median : 0.000   Median : 0.000  
   NATIVE_L19        NATIVE_L20        NATIVE_L21       NATIVE_L22    
 Min.   :  0.000   Min.   : 0.0000   Min.   :  0.00   Min.   : 0.000  
 1st Qu.:  0.000   1st Qu.: 0.0000   1st Qu.:  5.00   1st Qu.: 0.000  
 Median :  0.000   Median : 0.0000   Median : 15.00   Median : 0.000  
   NATIVE_L23       NATIVE_L24        NATIVE_L25        NATIVE_L26     
 Min.   : 0.000   Min.   :  0.000   Min.   :0.00000   Min.   : 0.0000  
 1st Qu.: 0.000   1st Qu.:  0.000   1st Qu.:0.00000   1st Qu.: 0.0000  
 Median : 0.000   Median :  0.000   Median :0.00000   Median : 0.0000  
   NATIVE_L27        NATIVE_L28       NATIVE_L29        NATIVE_L30    
 Min.   :  0.000   Min.   : 0.000   Min.   : 0.0000   Min.   : 0.000  
 1st Qu.:  0.000   1st Qu.: 0.000   1st Qu.: 0.0000   1st Qu.: 0.000  
 Median :  0.000   Median : 0.000   Median : 0.0000   Median : 5.000  
   NATIVE_L31       NATIVE_L32       NATIVE_L33       NATIVE_L34     
 Min.   :  0.00   Min.   : 0.000   Min.   :  0.00   Min.   :  0.000  
 1st Qu.:  5.00   1st Qu.: 0.000   1st Qu.:  5.00   1st Qu.:  0.000  
 Median : 10.00   Median : 0.000   Median : 15.00   Median :  5.000  
   NATIVE_L35       NATIVE_L36       NATIVE_L37       NATIVE_L38    
 Min.   : 0.000   Min.   :  0.00   Min.   : 0.000   Min.   : 0.000  
 1st Qu.: 0.000   1st Qu.: 10.00   1st Qu.: 0.000   1st Qu.: 0.000  
 Median : 0.000   Median : 25.00   Median : 0.000   Median : 0.000  
   NATIVE_L39        NATIVE_L40        NATIVE_L41       NATIVE_L42   
 Min.   : 0.0000   Min.   :0.00000   Min.   :  0.00   Min.   : 0.00  
 1st Qu.: 0.0000   1st Qu.:0.00000   1st Qu.: 25.00   1st Qu.: 5.00  
 Median : 0.0000   Median :0.00000   Median : 40.00   Median :10.00  
   NATIVE_L43        NATIVE_L44        NATIVE_L45       NATIVE_L46    
 Min.   :  0.000   Min.   :0.00000   Min.   : 0.000   Min.   : 0.000  
 1st Qu.:  0.000   1st Qu.:0.00000   1st Qu.: 0.000   1st Qu.: 0.000  
 Median :  5.000   Median :0.00000   Median : 0.000   Median : 5.000  
   NATIVE_L47      NATIVE_L48        NATIVE_L49        NATIVE_L50      NATIVE_L51    
 Min.   : 0.00   Min.   : 0.0000   Min.   : 0.0000   Min.   :  0.0   Min.   : 0.000  
 1st Qu.:10.00   1st Qu.: 0.0000   1st Qu.: 0.0000   1st Qu.: 35.0   1st Qu.: 0.000  
 Median :20.00   Median : 0.0000   Median : 0.0000   Median : 70.0   Median : 0.000  
   NATIVE_L52        NATIVE_L53       NATIVE_L54      NATIVE_L55       NATIVE_L56   
 Min.   :  0.000   Min.   :  0.00   Min.   :  0.0   Min.   : 0.000   Min.   : 0.00  
 1st Qu.:  0.000   1st Qu.:  0.00   1st Qu.:  0.0   1st Qu.: 0.000   1st Qu.: 0.00  
 Median :  0.000   Median :  5.00   Median :  0.0   Median : 0.000   Median : 0.00  
   NATIVE_L57       NATIVE_L58       NATIVE_L59    
 Min.   :0.0000   Min.   : 0.000   Min.   : 0.000  
 1st Qu.:0.0000   1st Qu.: 0.000   1st Qu.: 0.000  
 Median :0.0000   Median : 5.000   Median : 0.000  
 [ reached getOption("max.print") -- omitted 4 rows ]

Area data

Every phenomena can be measured at a location (ask yourself, what exists outside of space?).

In point pattern analysis, the unit of support is the point, and the source of randomness is the location itself. Many other forms of data are also collected at points. For instance, when the census collects information on population, at its most basic, the information can be georeferenced to an address, that is, a point.

In numerous applications, however, data are not reported at their fundamental unit of support, but rather are aggregated to some other geometry, for instance an area. This is done for several reasons, including the privacy and confidentiality of the data. Instead of reporting individual-level information, the information is reported for zoning systems that often are devised without consideration to any underlying social, natural, or economic processes.

Census data, for instance, is reported at different levels of geography. In Canada, the smallest publicly available geography is called a Dissemination Area or DA. A DA in Canada contains a population between 400 and 700 persons. Thus, instead of reporting that one person (or more) are located at a point (i.e., an address), the census reports the population for the DA. Other data are aggregated in similar ways (income, residential status, etc.)

At the highest level of aggregation, national level statistics are reported, for instance Gross Domestic Product, or GDP. Economic production is not evenly distributed across space; however, the national GDP does not distinguish regional variations in this process.

Ideally, a data analyst would work with data in its most fundamental support. This is not alway possible, and therefore many techniques have been developed to work with data that have been agregated to zones.

When working with areas, it is less practical to identify the area with the coordinates (as we did with points). After all, areas will be composed of lines and reporting all the relevant coordinates is impractical. Sometimes the geometric centroids of the areas are used instead.

More commonly, areas are assigned an index or unique identifier, so that a region will typically consist of a set of \(n\) areas as follows: \[ R = A_1 \cup A_2 \cup A_3 \cup ...\cup A_n. \]

The above is read as “the Region R is the union of Areas 1 to n”.

Regions can have a set of \(k\) attributes or variables associated with them, for instance: \[ \textbf{X}_i=[x_{i1}, x_{i2}, x_{i3},...,x_{ik}] \]

These attributes will typically be counts (e.g., number of people in a DA), or some summary measure of the underlying data (e.g., mean commute time).

Processes and area data

Imagine that data on income by household were collected as follows:

df <- data.frame(x = c(0.3, 0.4, 0.5, 0.6, 0.7), y = c(0.1, 0.4, 0.2, 0.5, 0.3), Income = c(30000, 30000, 100000, 100000, 100000))

Households are geocoded as points with coordinates x and y, whereas income is in dollars.

Plot the income as points (hover over the points to see the attributes):

p <- ggplot(data = df, aes(x = x, y = y, color = Income)) + 
  geom_point(shape = 17, size = 5) +
  coord_fixed()
ggplotly(p)
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

The underlying process is one of income sorting, with lower incomes to the west, and higher incomes to the east. This could be due to a geographical feature of the landscape (for instance, an escarpment), or the distribution of the housing stock (with a neighborhood that has more expensive houses). These are examples of a variable that responds to a common environmental factor. As an alternative, people may display a preference towards being near others that are similar to them (this is called homophily). When this happens, the variable responds to itself in space.

The quality of similarity or disimilarity between neighboring observations of the same variable in space is called spatial autocorrelation. You will learn more about this later on.

Another reason why variables reported for areas could display similarities in space is as an consequence of the zoning system.

Suppose for a moment that the data above can only be reported at the zonal level, perhaps because of privacy and confidentiality concerns. Thanks to the great talent of the designers of the zoning system (or a felicitous coincidence!), the zoning system is such that it is consistent with the underlying process of sorting. The zones, therefore, are as follows:

zones1 <- data.frame(x1=c(0.2, 0.45), x2=c(0.45, 0.80), y1=c(0.0, 0.0), y2=c(0.6, 0.6), Zone_ID = c('1','2'))

If you add these zones to the plot:

p <- ggplot() + 
  geom_rect(data = zones1, mapping = aes(xmin = x1, xmax = x2, ymin = y1, ymax = y2, fill = Zone_ID), alpha = 0.3) + 
  geom_point(data = df, aes(x = x, y = y, color = Income), shape = 17, size = 5) +
  coord_fixed()
ggplotly(p)
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

What is the mean income in zone 1? What is the mean income in zone 2? Not only are the summary measures of income highly representative of the observations they describe, the two zones are also highly distinct.

Imagine now that for whatever reason (lack of prior knowledge of the process, convenience for data collection, etc.) the zones instead are as follows:

zones2 <- data.frame(x1=c(0.2, 0.55), x2=c(0.55, 0.80), y1=c(0.0, 0.0), y2=c(0.6, 0.6), Zone_ID = c('1','2'))

If you plot these zones:

p <- ggplot() + 
  geom_rect(data = zones2, mapping = aes(xmin = x1, xmax = x2, ymin = y1, ymax = y2, fill = Zone_ID), alpha = 0.3) + 
  geom_point(data = df, aes(x = x, y = y, color = Income), shape = 17, size = 5) +
  coord_fixed()
ggplotly(p)
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

What is now the mean income of zone 1? What is the mean income of zone 2? The observations have not changed, and the generating spatial process remains the same. You will notice, however, that the summary measures for the two zones are more similar in this case than they were when the zones more closely captured the underlying process.

Visualizing area data: choropleth maps

The initial step when working with spatial area data, perhaps, is to visualize the data.

Commonly, area data are visualized by means of choropleth maps. A choropleth map is a map of the polygons that form the areas in the region, each colored in a way to represent the value of an underlying variable.

Lets use ggplot2 to create a choropleth map of population in Hamilton. Notice that the fill color for the polygons is given by cutting the values of POPULATION in five equal segments. In other words, the colors represent zones in the bottom 20% of population, zones in the next 20%, and so on, so that the darkest zones are those with populations so large as to be in the top 20% of the population distribution:

ggplot() + geom_polygon(data = Hamilton_CT.t, aes(x = long, y = lat, group = group, fill = cut_number(POPULATION, 5)),color = NA, size = 0.1) +
  scale_fill_brewer(palette = "YlOrRd") +
  coord_fixed() +
  theme(legend.position = "bottom") +
  labs(fill = "Population")

Inspecting the map above, would you say that the distribution of population is random, or not random? If not random, what do you think might be an underlying process for the distribution of population.

Often, creating a choropleth map using the absolute value of a variable can be somewhat misleading. As seen in the map above, the zones with the largest population are also usually large zones. Any process that you might think of will be confounded by the size of the zones. For this reason, it is often more informative when creating a choropleth map to use a variable that is a rate, for instance population divided by area to give population density:

pop_den.map <- ggplot() + geom_polygon(data = Hamilton_CT.t, aes(x = long, y = lat, group = group, fill = cut_number(POPULATION/AREA, 5)),color = "white", size = 0.1) +
  scale_fill_brewer(palette = "YlOrRd") +
  coord_fixed() +
  theme(legend.position = "bottom") +
  labs(fill = "Pop Density")
pop_den.map

It can be seen now that the population density is higher in the more central parts of Hamilton, Burlington, Dundas, etc. Does the map look random? If not, what might be an underlying process that explains the variations in population density in a city like Hamilton?

Other times, it is appropriate to standardize instead of by area, by what might be called the population at risk. For instance, lets say that we wanted to explore the distribution of the population of older adults (say, 65 and older). In this case, normalizing not by area, but by the total population, would remove the “size” effect, giving a proportion:

ggplot() + geom_polygon(data = Hamilton_CT.t, aes(x = long, y = lat, group = group, fill = cut_number((AGE_65_TO_ + AGE_70_TO_ + AGE_75_TO_ + AGE_80_TO_ + AGE_85)/POPULATION, 5)),color = NA, size = 0.1) +
  scale_fill_brewer(palette = "YlOrRd") +
  coord_fixed() +
  theme(legend.position = "bottom") +
  labs(fill = "Prop Age 65+")

Do you notice a pattern in the distribution of seniors in the Hamilton, CMA?

There are a few things to keep in mind when creating choroplet maps.

First, what classification scheme to use, with how many classes, and what colors?

The examples above were all created using a classification scheme based on the quintiles of the distribution. As noted above, these are obtained by dividing the sample into 5 equal parts to give bottom 20%, etc., of observations. The quintiles are a particular form of a statistical measure known as quantiles, of which the median is value obtained when the sample is divided in two equal sized parts. Other classification schemes may include the mean, standard deviation, and so on.

In terms of how many classes to use, often there is little point in using more than six or seven classes, because the human eye cannot distinguish color differences at a much higher resolution.

The colors are a matter of style, but there are coloring schemes that are colorblind safe (see here).

Secondly, when the zoning system is irregular (as opposed to, say, a raster), large zones can easily become dominant. In effect, much detail in the maps above is lost for small zones, whereas large zones, especially if similarly colored, may mislead the eye as to their relative frequency.

Another mapping technique, the cartogram, is meant to reduce the issues with small-large zones.

Visualizing area data: cartogram

A cartogram is a map where the size of the zones is adjusted so that instead of being the land area, it is proportional to some other variable of interest.

Lets illustrate the idea behind the cartogram here.

In the maps above, the zones are faithful to their geographical properties. Unfortunately, this obscured the relevance of small zones. A cartogram can be weighted by another variable, say for instance, the population. In this way, the size of the zones will depend on the total population.

Cartograms are implemented in R in the package cartogram.

CT_pop_cartogram <- cartogram(shp = Hamilton_CT, weight = "POPULATION")
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 1: 5.94063097656517
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 2: 4.22282836609772
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 3: 3.24121918122005
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 4: 2.70487592121738
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 5: 2.44050500280525
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 6: 2.28238579460187
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 7: 2.14591026585647
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 8: 1.95255176465899
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 9: 1.8186943555214
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 10: 1.73775203417466
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 11: 1.64845060853967
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 12: 1.45162213155545
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 13: 1.37178691507706
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 14: 1.32738198642848
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 15: 1.29727221750122

Notice that the value of the function cartogram (i.e., its output) is a SpatialPolygonsDataFrame. This object needs to be tidied if we wish to use ggplot2 to visualize it:

CT_pop_cartogram.t <- tidy(CT_pop_cartogram, region = "TRACT")
CT_pop_cartogram.t <- rename(CT_pop_cartogram.t, TRACT = id)

As before, the data were stripped from the tidied version of the dataframe, so they need to be restored:

CT_pop_cartogram.t <- left_join(CT_pop_cartogram.t, CT_pop_cartogram@data, by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector

Plotting the cartogram:

ggplot() + geom_polygon(data = CT_pop_cartogram.t, aes(x = long, y = lat, group = group, fill = cut_number(POPULATION, 5)), color = "white", size = 0.1) +
  scale_fill_brewer(palette = "YlOrRd") +
  coord_fixed() +
  theme(legend.position = "bottom") +
  labs(fill = "Population")

Notice how the size of the zones has been adjusted.

The cartogram can be combined with coloring schemes, as in choropleth maps:

CT_popden_cartogram <- cartogram(Hamilton_CT, weight = "POP_DENSIT")
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 1: 29.0772344366743
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 2: 26.933147928614
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 3: 25.1986261892098
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 4: 23.7327939549969
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 5: 22.4463390026744
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 6: 21.2818852763495
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 7: 20.2025834378354
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 8: 19.1839656200552
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 9: 18.2099242308777
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 10: 17.2709049215263
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 11: 16.3609019577218
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 12: 15.4772258019554
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 13: 14.619308950628
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 14: 13.7881685736231
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 15: 12.9857607680246

Tidy and restore the data:

CT_popden_cartogram.t <- tidy(CT_popden_cartogram, region = "TRACT")
CT_popden_cartogram.t <- rename(CT_popden_cartogram.t, TRACT = id)
CT_popden_cartogram.t <- left_join(CT_popden_cartogram.t, CT_popden_cartogram@data, by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector
pop_den.cartogram <- ggplot() + geom_polygon(data = CT_popden_cartogram.t, aes(x = long, y = lat, group = group, fill = cut_number(POP_DENSIT, 5)),color = "white", size = 0.1) +
  scale_fill_brewer(palette = "YlOrRd") +
  coord_fixed() +
  theme(legend.position = "bottom") +
  labs(fill = "Pop Density")
pop_den.cartogram

By combining a cartogram with choropleth mapping, it becomes easier to appreciate the way high population density is concentrated in the central parts of Hamilton, Burlington, etc.

grid.arrange(pop_den.map, pop_den.cartogram, nrow = 1)

This concludes Practice 9.

LS0tDQp0aXRsZTogIjA5IEFyZWEgRGF0YSBJIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KI0ludHJvZHVjdGlvbg0KDQpOT1RFOiBUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KSW4gbGFzdCBmZXcgcHJhY3RpY2VzL3Nlc3Npb25zLCB5b3UgbGVhcm5lZCBhYm91dCBzcGF0aWFsIHBvaW50IHBhdHRlcm5zLiBUaGUgbmV4dCBmZXcgc2Vzc2lvbnMgd2lsbCBjb25jZW50cmF0ZSBvbiBfYXJlYSBkYXRhXy4NCg0KRm9yIHRoaXMgcHJhY3RpY2UgeW91IHdpbGwgbmVlZCB0aGUgZm9sbG93aW5nOg0KDQoqIFRoaXMgUiBtYXJrZG93biBub3RlYm9vay4NCiogQSBzaGFwZSBmaWxlIGNhbGxlZCAiSGFtaWx0b24gQ01BIENUIg0KDQpUaGlzIGRhdGFzZXQgaW5jbHVkZXMgdGhlIHNwYXRpYWwgaW5mb3JtYXRpb24gZm9yIHRoZSBjZW5zdXMgdHJhY3RzIGluIHRoZSBIYW1pbHRvbiBDZW5zdXMgTWV0cm9wb2xpdGFuIEFyZWEgKGFzIHBvbHlnb25zKSwgYW5kIGEgaG9zdCBvZiBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgZnJvbSB0aGUgY2Vuc3VzIG9mIENhbmFkYSwgaW5jbHVkaW5nIHBvcHVsYXRpb24gYW5kIGxhbmd1YWdlcy4NCg0KI0xlYXJuaW5nIG9iamVjdGl2ZXMNCg0KSW4gdGhpcyBwcmFjdGljZSwgeW91IHdpbGwgbGVhcm46DQoNCjEuIEEgZm9ybWFsIGRlZmluaXRpb24gb2YgYXJlYSBkYXRhLg0KMi4gUHJvY2Vzc2VzIGFuZCBhcmVhIGRhdGEuDQozLiBWaXN1YWxpemluZyBhcmVhIGRhdGE6IENob3JvcGxldGggbWFwcy4NCjQuIFZpc3VhbGl6aW5nIGFyZWEgZGF0YTogQ2FydG9ncmFtcy4NCg0KI1N1Z2dlc3RlZCByZWFkaW5nDQoNCk8nU3VsbGl2YW4gRCBhbmQgVW53aW4gRCAoMjAxMCkgR2VvZ3JhcGhpYyBJbmZvcm1hdGlvbiBBbmFseXNpcywgMm5kIEVkaXRpb24sIENoYXB0ZXIgNy4gSm9obiBXaWxleSAmIFNvbnM6IE5ldyBKZXJzZXkuDQoNCiNQcmVsaW1pbmFyaWVzDQoNCkFzIHVzdWFsLCBpdCBpcyBnb29kIHByYWN0aWNlIHRvIGNsZWFyIHRoZSB3b3JraW5nIHNwYWNlIHRvIG1ha2Ugc3VyZSB0aGF0IHlvdSBkbyBub3QgaGF2ZSBleHRyYW5lb3VzIGl0ZW1zIHRoZXJlIHdoZW4geW91IGJlZ2luIHlvdXIgd29yay4gVGhlIGNvbW1hbmQgaW4gUiB0byBjbGVhciB0aGUgd29ya3NwYWNlIGlzIGBybWAgKGZvciAicmVtb3ZlIiksIGZvbGxvd2VkIGJ5IGEgbGlzdCBvZiBpdGVtcyB0byBiZSByZW1vdmVkLiBUbyBjbGVhciB0aGUgd29ya3NwYWNlIGZyb20gX2FsbF8gb2JqZWN0cywgZG8gdGhlIGZvbGxvd2luZzoNCmBgYHtyfQ0Kcm0obGlzdCA9IGxzKCkpDQpgYGANCg0KTm90ZSB0aGF0IGBscygpYCBsaXN0cyBhbGwgb2JqZWN0cyBjdXJyZW50bHkgb24gdGhlIHdvcnNwYWNlLg0KDQpMb2FkIHRoZSBsaWJyYXJpZXMgeW91IHdpbGwgdXNlIGluIHRoaXMgYWN0aXZpdHk6DQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoY2FydG9ncmFtKQ0KbGlicmFyeShncmlkRXh0cmEpDQpgYGANCg0KUmVhZCB0aGUgZGF0YSB0aGF0IHlvdSB3aWxsIHVzZSBmb3IgdGhpcyBwcmFjdGljZS4gVGhpcyBpcyBhbiBFc3JpIHNoYXBlIGZpbGUgdGhhdCB3aWxsIGJlIHNhdmVkIGFzIGFuIG9iamVjdCBvZiBjbGFzcyBgU3BhdGlhbFBvbHlnb25EYXRhRnJhbWVgLiBUaGUgZnVuY3Rpb24gdXNlZCB0byByZWFkIEVzcmkgc2hhcGUgZmlsZXMgaXMgYHJnZGFsOjpyZWFkT0dSYC4gU2V0dGluZyBgaW50ZWdlcjY0YCB0byAiYWxsb3cubG9zcyIga2VlcHMgdGhlIGRhdGEgYXMgaW50ZWdlcnMgYXMgb3Bwb3NlZCB0byBjaGFuZ2luZyB0byBmYWN0b3JzIG9yIHN0cmluZ3M6DQpgYGB7cn0NCkhhbWlsdG9uX0NUIDwtIHJlYWRPR1IoIi4iLCBsYXllciA9ICJIYW1pbHRvbiBDTUEgQ1QiLCBpbnRlZ2VyNjQgPSAiYWxsb3cubG9zcyIpDQpgYGANCg0KVG8gdXNlIHRoZSBwbG90dGluZyBmdW5jdGlvbnMgb2YgYGdncGxvdDJgLCB0aGUgYFNwYXRpYWxQb2x5Z29uRGF0YUZyYW1lYCBuZWVkcyB0byBiZSAidGlkaWVkIiBieSBtZWFucyBvZiB0aGUgYHRpZHlgIGZ1bmN0aW9uIG9mIHRoZSBgYnJvb21gIHBhY2thZ2U6DQpgYGB7cn0NCkhhbWlsdG9uX0NULnQgPC0gdGlkeShIYW1pbHRvbl9DVCwgcmVnaW9uID0gIlRSQUNUIikNCkhhbWlsdG9uX0NULnQgPC0gZHBseXI6OnJlbmFtZShIYW1pbHRvbl9DVC50LCBUUkFDVCA9IGlkKQ0KYGBgDQoNClRpZHlpbmcgdGhlIHNwYXRpYWwgZGF0YWZyYW1lIHN0cmlwcyBpdCBmcm9tIHRoZSBub24tc3BhdGlhbCBpbmZvcm1hdGlvbiwgYnV0IHdlIGNhbiBhZGQgYWxsIHRoZSBkYXRhIGJ5IG1lYW5zIG9mIHRoZSBgbGVmdF9qb2luYCBmdW5jdGlvbjoNCmBgYHtyfQ0KSGFtaWx0b25fQ1QudCA8LSBsZWZ0X2pvaW4oSGFtaWx0b25fQ1QudCwgSGFtaWx0b25fQ1RAZGF0YSwgYnkgPSAiVFJBQ1QiKQ0KYGBgDQoNCk5vdyB0aGUgdGlkeSBkYXRhZnJhbWUgYEhhbWlsdG9uX0RBLnRgIGNvbnRhaW5zIHRoZSBzcGF0aWFsIGluZm9ybWF0aW9uIGFuZCB0aGUgZGF0YS4NCg0KWW91IGNhbiBxdWlja2x5IHZlcmlmeSB0aGUgY29udGVudHMgb2YgdGhlIGRhdGFmcmFtZSBieSBtZWFucyBvZiBgc3VtbWFyeWA6DQpgYGB7cn0NCnN1bW1hcnkoSGFtaWx0b25fQ1QudCkNCmBgYA0KDQojQXJlYSBkYXRhDQoNCkV2ZXJ5IHBoZW5vbWVuYSBjYW4gYmUgbWVhc3VyZWQgYXQgYSBsb2NhdGlvbiAoYXNrIHlvdXJzZWxmLCB3aGF0IGV4aXN0cyBvdXRzaWRlIG9mIHNwYWNlPykuDQoNCkluIHBvaW50IHBhdHRlcm4gYW5hbHlzaXMsIHRoZSBfdW5pdCBvZiBzdXBwb3J0XyBpcyB0aGUgcG9pbnQsIGFuZCB0aGUgc291cmNlIG9mIHJhbmRvbW5lc3MgaXMgdGhlIGxvY2F0aW9uIGl0c2VsZi4gTWFueSBvdGhlciBmb3JtcyBvZiBkYXRhIGFyZSBhbHNvIGNvbGxlY3RlZCBhdCBwb2ludHMuIEZvciBpbnN0YW5jZSwgd2hlbiB0aGUgY2Vuc3VzIGNvbGxlY3RzIGluZm9ybWF0aW9uIG9uIHBvcHVsYXRpb24sIGF0IGl0cyBtb3N0IGJhc2ljLCB0aGUgaW5mb3JtYXRpb24gY2FuIGJlIGdlb3JlZmVyZW5jZWQgdG8gYW4gYWRkcmVzcywgdGhhdCBpcywgYSBwb2ludC4NCg0KSW4gbnVtZXJvdXMgYXBwbGljYXRpb25zLCBob3dldmVyLCBkYXRhIGFyZSBub3QgcmVwb3J0ZWQgYXQgdGhlaXIgZnVuZGFtZW50YWwgdW5pdCBvZiBzdXBwb3J0LCBidXQgcmF0aGVyIGFyZSBhZ2dyZWdhdGVkIHRvIHNvbWUgb3RoZXIgZ2VvbWV0cnksIGZvciBpbnN0YW5jZSBhbiBhcmVhLiBUaGlzIGlzIGRvbmUgZm9yIHNldmVyYWwgcmVhc29ucywgaW5jbHVkaW5nIHRoZSBwcml2YWN5IGFuZCBjb25maWRlbnRpYWxpdHkgb2YgdGhlIGRhdGEuIEluc3RlYWQgb2YgcmVwb3J0aW5nIGluZGl2aWR1YWwtbGV2ZWwgaW5mb3JtYXRpb24sIHRoZSBpbmZvcm1hdGlvbiBpcyByZXBvcnRlZCBmb3Igem9uaW5nIHN5c3RlbXMgdGhhdCBvZnRlbiBhcmUgZGV2aXNlZCB3aXRob3V0IGNvbnNpZGVyYXRpb24gdG8gYW55IHVuZGVybHlpbmcgc29jaWFsLCBuYXR1cmFsLCBvciBlY29ub21pYyBwcm9jZXNzZXMuDQoNCkNlbnN1cyBkYXRhLCBmb3IgaW5zdGFuY2UsIGlzIHJlcG9ydGVkIGF0IGRpZmZlcmVudCBsZXZlbHMgb2YgZ2VvZ3JhcGh5LiBJbiBDYW5hZGEsIHRoZSBzbWFsbGVzdCBwdWJsaWNseSBhdmFpbGFibGUgZ2VvZ3JhcGh5IGlzIGNhbGxlZCBhIF9EaXNzZW1pbmF0aW9uIEFyZWFfIG9yIFtEQV0oaHR0cDovL3d3dzEyLnN0YXRjYW4uZ2MuY2EvY2Vuc3VzLXJlY2Vuc2VtZW50LzIwMTEvcmVmL2RpY3QvZ2VvMDIxLWVuZy5jZm0pLiBBIERBIGluIENhbmFkYSBjb250YWlucyBhIHBvcHVsYXRpb24gYmV0d2VlbiA0MDAgYW5kIDcwMCBwZXJzb25zLiBUaHVzLCBpbnN0ZWFkIG9mIHJlcG9ydGluZyB0aGF0IG9uZSBwZXJzb24gKG9yIG1vcmUpIGFyZSBsb2NhdGVkIGF0IGEgcG9pbnQgKGkuZS4sIGFuIGFkZHJlc3MpLCB0aGUgY2Vuc3VzIHJlcG9ydHMgdGhlIHBvcHVsYXRpb24gZm9yIHRoZSBEQS4gT3RoZXIgZGF0YSBhcmUgYWdncmVnYXRlZCBpbiBzaW1pbGFyIHdheXMgKGluY29tZSwgcmVzaWRlbnRpYWwgc3RhdHVzLCBldGMuKQ0KDQpBdCB0aGUgaGlnaGVzdCBsZXZlbCBvZiBhZ2dyZWdhdGlvbiwgbmF0aW9uYWwgbGV2ZWwgc3RhdGlzdGljcyBhcmUgcmVwb3J0ZWQsIGZvciBpbnN0YW5jZSBHcm9zcyBEb21lc3RpYyBQcm9kdWN0LCBvciBHRFAuIEVjb25vbWljIHByb2R1Y3Rpb24gaXMgbm90IGV2ZW5seSBkaXN0cmlidXRlZCBhY3Jvc3Mgc3BhY2U7IGhvd2V2ZXIsIHRoZSBuYXRpb25hbCBHRFAgZG9lcyBub3QgZGlzdGluZ3Vpc2ggcmVnaW9uYWwgdmFyaWF0aW9ucyBpbiB0aGlzIHByb2Nlc3MuDQoNCklkZWFsbHksIGEgZGF0YSBhbmFseXN0IHdvdWxkIHdvcmsgd2l0aCBkYXRhIGluIGl0cyBtb3N0IGZ1bmRhbWVudGFsIHN1cHBvcnQuIFRoaXMgaXMgbm90IGFsd2F5IHBvc3NpYmxlLCBhbmQgdGhlcmVmb3JlIG1hbnkgdGVjaG5pcXVlcyBoYXZlIGJlZW4gZGV2ZWxvcGVkIHRvIHdvcmsgd2l0aCBkYXRhIHRoYXQgaGF2ZSBiZWVuIGFncmVnYXRlZCB0byB6b25lcy4NCg0KV2hlbiB3b3JraW5nIHdpdGggYXJlYXMsIGl0IGlzIGxlc3MgcHJhY3RpY2FsIHRvIGlkZW50aWZ5IHRoZSBhcmVhIHdpdGggdGhlIGNvb3JkaW5hdGVzIChhcyB3ZSBkaWQgd2l0aCBwb2ludHMpLiBBZnRlciBhbGwsIGFyZWFzIHdpbGwgYmUgY29tcG9zZWQgb2YgbGluZXMgYW5kIHJlcG9ydGluZyBhbGwgdGhlIHJlbGV2YW50IGNvb3JkaW5hdGVzIGlzIGltcHJhY3RpY2FsLiBTb21ldGltZXMgdGhlIGdlb21ldHJpYyBjZW50cm9pZHMgb2YgdGhlIGFyZWFzIGFyZSB1c2VkIGluc3RlYWQuDQoNCk1vcmUgY29tbW9ubHksIGFyZWFzIGFyZSBhc3NpZ25lZCBhbiBpbmRleCBvciB1bmlxdWUgaWRlbnRpZmllciwgc28gdGhhdCBhIHJlZ2lvbiB3aWxsIHR5cGljYWxseSBjb25zaXN0IG9mIGEgc2V0IG9mICRuJCBhcmVhcyBhcyBmb2xsb3dzOg0KJCQNClIgPSBBXzEgXGN1cCBBXzIgXGN1cCBBXzMgXGN1cCAuLi5cY3VwIEFfbi4NCiQkDQoNClRoZSBhYm92ZSBpcyByZWFkIGFzICJ0aGUgUmVnaW9uIFIgaXMgdGhlIHVuaW9uIG9mIEFyZWFzIDEgdG8gbiIuDQoNClJlZ2lvbnMgY2FuIGhhdmUgYSBzZXQgb2YgJGskIGF0dHJpYnV0ZXMgb3IgdmFyaWFibGVzIGFzc29jaWF0ZWQgd2l0aCB0aGVtLCBmb3IgaW5zdGFuY2U6DQokJA0KXHRleHRiZntYfV9pPVt4X3tpMX0sIHhfe2kyfSwgeF97aTN9LC4uLix4X3tpa31dDQokJA0KDQpUaGVzZSBhdHRyaWJ1dGVzIHdpbGwgdHlwaWNhbGx5IGJlIGNvdW50cyAoZS5nLiwgbnVtYmVyIG9mIHBlb3BsZSBpbiBhIERBKSwgb3Igc29tZSBzdW1tYXJ5IG1lYXN1cmUgb2YgdGhlIHVuZGVybHlpbmcgZGF0YSAoZS5nLiwgbWVhbiBjb21tdXRlIHRpbWUpLg0KDQojUHJvY2Vzc2VzIGFuZCBhcmVhIGRhdGENCg0KSW1hZ2luZSB0aGF0IGRhdGEgb24gaW5jb21lIGJ5IGhvdXNlaG9sZCB3ZXJlIGNvbGxlY3RlZCBhcyBmb2xsb3dzOg0KYGBge3J9DQpkZiA8LSBkYXRhLmZyYW1lKHggPSBjKDAuMywgMC40LCAwLjUsIDAuNiwgMC43KSwgeSA9IGMoMC4xLCAwLjQsIDAuMiwgMC41LCAwLjMpLCBJbmNvbWUgPSBjKDMwMDAwLCAzMDAwMCwgMTAwMDAwLCAxMDAwMDAsIDEwMDAwMCkpDQpgYGANCg0KSG91c2Vob2xkcyBhcmUgZ2VvY29kZWQgYXMgcG9pbnRzIHdpdGggY29vcmRpbmF0ZXMgYHhgIGFuZCBgeWAsIHdoZXJlYXMgaW5jb21lIGlzIGluIGRvbGxhcnMuDQoNClBsb3QgdGhlIGluY29tZSBhcyBwb2ludHMgKGhvdmVyIG92ZXIgdGhlIHBvaW50cyB0byBzZWUgdGhlIGF0dHJpYnV0ZXMpOg0KYGBge3J9DQpwIDwtIGdncGxvdChkYXRhID0gZGYsIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gSW5jb21lKSkgKyANCiAgZ2VvbV9wb2ludChzaGFwZSA9IDE3LCBzaXplID0gNSkgKw0KICBjb29yZF9maXhlZCgpDQpnZ3Bsb3RseShwKQ0KYGBgDQoNClRoZSB1bmRlcmx5aW5nIHByb2Nlc3MgaXMgb25lIG9mIGluY29tZSBzb3J0aW5nLCB3aXRoIGxvd2VyIGluY29tZXMgdG8gdGhlIHdlc3QsIGFuZCBoaWdoZXIgaW5jb21lcyB0byB0aGUgZWFzdC4gVGhpcyBjb3VsZCBiZSBkdWUgdG8gYSBnZW9ncmFwaGljYWwgZmVhdHVyZSBvZiB0aGUgbGFuZHNjYXBlIChmb3IgaW5zdGFuY2UsIGFuIGVzY2FycG1lbnQpLCBvciB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBob3VzaW5nIHN0b2NrICh3aXRoIGEgbmVpZ2hib3Job29kIHRoYXQgaGFzIG1vcmUgZXhwZW5zaXZlIGhvdXNlcykuIFRoZXNlIGFyZSBleGFtcGxlcyBvZiBhIHZhcmlhYmxlIHRoYXQgcmVzcG9uZHMgdG8gYSBjb21tb24gZW52aXJvbm1lbnRhbCBmYWN0b3IuIEFzIGFuIGFsdGVybmF0aXZlLCBwZW9wbGUgbWF5IGRpc3BsYXkgYSBwcmVmZXJlbmNlIHRvd2FyZHMgYmVpbmcgbmVhciBvdGhlcnMgdGhhdCBhcmUgc2ltaWxhciB0byB0aGVtICh0aGlzIGlzIGNhbGxlZCBob21vcGhpbHkpLiBXaGVuIHRoaXMgaGFwcGVucywgdGhlIHZhcmlhYmxlIHJlc3BvbmRzIHRvIGl0c2VsZiBpbiBzcGFjZS4NCg0KVGhlIHF1YWxpdHkgb2Ygc2ltaWxhcml0eSBvciBkaXNpbWlsYXJpdHkgYmV0d2VlbiBuZWlnaGJvcmluZyBvYnNlcnZhdGlvbnMgb2YgdGhlIHNhbWUgdmFyaWFibGUgaW4gc3BhY2UgaXMgY2FsbGVkIF9zcGF0aWFsIGF1dG9jb3JyZWxhdGlvbl8uIFlvdSB3aWxsIGxlYXJuIG1vcmUgYWJvdXQgdGhpcyBsYXRlciBvbi4NCg0KQW5vdGhlciByZWFzb24gd2h5IHZhcmlhYmxlcyByZXBvcnRlZCBmb3IgYXJlYXMgY291bGQgZGlzcGxheSBzaW1pbGFyaXRpZXMgaW4gc3BhY2UgaXMgYXMgYW4gY29uc2VxdWVuY2Ugb2YgdGhlIHpvbmluZyBzeXN0ZW0uDQoNClN1cHBvc2UgZm9yIGEgbW9tZW50IHRoYXQgdGhlIGRhdGEgYWJvdmUgY2FuIG9ubHkgYmUgcmVwb3J0ZWQgYXQgdGhlIHpvbmFsIGxldmVsLCBwZXJoYXBzIGJlY2F1c2Ugb2YgcHJpdmFjeSBhbmQgY29uZmlkZW50aWFsaXR5IGNvbmNlcm5zLiBUaGFua3MgdG8gdGhlIGdyZWF0IHRhbGVudCBvZiB0aGUgZGVzaWduZXJzIG9mIHRoZSB6b25pbmcgc3lzdGVtIChvciBhIGZlbGljaXRvdXMgY29pbmNpZGVuY2UhKSwgdGhlIHpvbmluZyBzeXN0ZW0gaXMgc3VjaCB0aGF0IGl0IGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgdW5kZXJseWluZyBwcm9jZXNzIG9mIHNvcnRpbmcuIFRoZSB6b25lcywgdGhlcmVmb3JlLCBhcmUgYXMgZm9sbG93czoNCmBgYHtyfQ0Kem9uZXMxIDwtIGRhdGEuZnJhbWUoeDE9YygwLjIsIDAuNDUpLCB4Mj1jKDAuNDUsIDAuODApLCB5MT1jKDAuMCwgMC4wKSwgeTI9YygwLjYsIDAuNiksIFpvbmVfSUQgPSBjKCcxJywnMicpKQ0KYGBgDQoNCklmIHlvdSBhZGQgdGhlc2Ugem9uZXMgdG8gdGhlIHBsb3Q6DQpgYGB7cn0NCnAgPC0gZ2dwbG90KCkgKyANCiAgZ2VvbV9yZWN0KGRhdGEgPSB6b25lczEsIG1hcHBpbmcgPSBhZXMoeG1pbiA9IHgxLCB4bWF4ID0geDIsIHltaW4gPSB5MSwgeW1heCA9IHkyLCBmaWxsID0gWm9uZV9JRCksIGFscGhhID0gMC4zKSArIA0KICBnZW9tX3BvaW50KGRhdGEgPSBkZiwgYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSBJbmNvbWUpLCBzaGFwZSA9IDE3LCBzaXplID0gNSkgKw0KICBjb29yZF9maXhlZCgpDQpnZ3Bsb3RseShwKQ0KDQpgYGANCg0KV2hhdCBpcyB0aGUgbWVhbiBpbmNvbWUgaW4gem9uZSAxPyBXaGF0IGlzIHRoZSBtZWFuIGluY29tZSBpbiB6b25lIDI/IE5vdCBvbmx5IGFyZSB0aGUgc3VtbWFyeSBtZWFzdXJlcyBvZiBpbmNvbWUgaGlnaGx5IHJlcHJlc2VudGF0aXZlIG9mIHRoZSBvYnNlcnZhdGlvbnMgdGhleSBkZXNjcmliZSwgdGhlIHR3byB6b25lcyBhcmUgYWxzbyBoaWdobHkgZGlzdGluY3QuDQoNCkltYWdpbmUgbm93IHRoYXQgZm9yIHdoYXRldmVyIHJlYXNvbiAobGFjayBvZiBwcmlvciBrbm93bGVkZ2Ugb2YgdGhlIHByb2Nlc3MsIGNvbnZlbmllbmNlIGZvciBkYXRhIGNvbGxlY3Rpb24sIGV0Yy4pIHRoZSB6b25lcyBpbnN0ZWFkIGFyZSBhcyBmb2xsb3dzOg0KYGBge3J9DQp6b25lczIgPC0gZGF0YS5mcmFtZSh4MT1jKDAuMiwgMC41NSksIHgyPWMoMC41NSwgMC44MCksIHkxPWMoMC4wLCAwLjApLCB5Mj1jKDAuNiwgMC42KSwgWm9uZV9JRCA9IGMoJzEnLCcyJykpDQpgYGANCg0KSWYgeW91IHBsb3QgdGhlc2Ugem9uZXM6DQpgYGB7cn0NCnAgPC0gZ2dwbG90KCkgKyANCiAgZ2VvbV9yZWN0KGRhdGEgPSB6b25lczIsIG1hcHBpbmcgPSBhZXMoeG1pbiA9IHgxLCB4bWF4ID0geDIsIHltaW4gPSB5MSwgeW1heCA9IHkyLCBmaWxsID0gWm9uZV9JRCksIGFscGhhID0gMC4zKSArIA0KICBnZW9tX3BvaW50KGRhdGEgPSBkZiwgYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSBJbmNvbWUpLCBzaGFwZSA9IDE3LCBzaXplID0gNSkgKw0KICBjb29yZF9maXhlZCgpDQpnZ3Bsb3RseShwKQ0KDQpgYGANCg0KV2hhdCBpcyBub3cgdGhlIG1lYW4gaW5jb21lIG9mIHpvbmUgMT8gV2hhdCBpcyB0aGUgbWVhbiBpbmNvbWUgb2Ygem9uZSAyPyBUaGUgb2JzZXJ2YXRpb25zIGhhdmUgbm90IGNoYW5nZWQsIGFuZCB0aGUgZ2VuZXJhdGluZyBzcGF0aWFsIHByb2Nlc3MgcmVtYWlucyB0aGUgc2FtZS4gWW91IHdpbGwgbm90aWNlLCBob3dldmVyLCB0aGF0IHRoZSBzdW1tYXJ5IG1lYXN1cmVzIGZvciB0aGUgdHdvIHpvbmVzIGFyZSBtb3JlIHNpbWlsYXIgaW4gdGhpcyBjYXNlIHRoYW4gdGhleSB3ZXJlIHdoZW4gdGhlIHpvbmVzIG1vcmUgY2xvc2VseSBjYXB0dXJlZCB0aGUgdW5kZXJseWluZyBwcm9jZXNzLg0KDQojIFZpc3VhbGl6aW5nIGFyZWEgZGF0YTogY2hvcm9wbGV0aCBtYXBzDQoNClRoZSBpbml0aWFsIHN0ZXAgd2hlbiB3b3JraW5nIHdpdGggc3BhdGlhbCBhcmVhIGRhdGEsIHBlcmhhcHMsIGlzIHRvIHZpc3VhbGl6ZSB0aGUgZGF0YS4NCg0KQ29tbW9ubHksIGFyZWEgZGF0YSBhcmUgdmlzdWFsaXplZCBieSBtZWFucyBvZiBjaG9yb3BsZXRoIG1hcHMuIEEgY2hvcm9wbGV0aCBtYXAgaXMgYSBtYXAgb2YgdGhlIHBvbHlnb25zIHRoYXQgZm9ybSB0aGUgYXJlYXMgaW4gdGhlIHJlZ2lvbiwgZWFjaCBjb2xvcmVkIGluIGEgd2F5IHRvIHJlcHJlc2VudCB0aGUgdmFsdWUgb2YgYW4gdW5kZXJseWluZyB2YXJpYWJsZS4gDQoNCkxldHMgdXNlIGBnZ3Bsb3QyYCB0byBjcmVhdGUgYSBjaG9yb3BsZXRoIG1hcCBvZiBwb3B1bGF0aW9uIGluIEhhbWlsdG9uLiBOb3RpY2UgdGhhdCB0aGUgZmlsbCBjb2xvciBmb3IgdGhlIHBvbHlnb25zIGlzIGdpdmVuIGJ5IGN1dHRpbmcgdGhlIHZhbHVlcyBvZiBgUE9QVUxBVElPTmAgaW4gZml2ZSBlcXVhbCBzZWdtZW50cy4gSW4gb3RoZXIgd29yZHMsIHRoZSBjb2xvcnMgcmVwcmVzZW50IHpvbmVzIGluIHRoZSBib3R0b20gMjAlIG9mIHBvcHVsYXRpb24sIHpvbmVzIGluIHRoZSBuZXh0IDIwJSwgYW5kIHNvIG9uLCBzbyB0aGF0IHRoZSBkYXJrZXN0IHpvbmVzIGFyZSB0aG9zZSB3aXRoIHBvcHVsYXRpb25zIHNvIGxhcmdlIGFzIHRvIGJlIGluIHRoZSB0b3AgMjAlIG9mIHRoZSBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbjoNCmBgYHtyfQ0KZ2dwbG90KCkgKyBnZW9tX3BvbHlnb24oZGF0YSA9IEhhbWlsdG9uX0NULnQsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGN1dF9udW1iZXIoUE9QVUxBVElPTiwgNSkpLGNvbG9yID0gTkEsIHNpemUgPSAwLjEpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJZbE9yUmQiKSArDQogIGNvb3JkX2ZpeGVkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBsYWJzKGZpbGwgPSAiUG9wdWxhdGlvbiIpDQpgYGANCg0KSW5zcGVjdGluZyB0aGUgbWFwIGFib3ZlLCB3b3VsZCB5b3Ugc2F5IHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwb3B1bGF0aW9uIGlzIHJhbmRvbSwgb3Igbm90IHJhbmRvbT8gSWYgbm90IHJhbmRvbSwgd2hhdCBkbyB5b3UgdGhpbmsgbWlnaHQgYmUgYW4gdW5kZXJseWluZyBwcm9jZXNzIGZvciB0aGUgZGlzdHJpYnV0aW9uIG9mIHBvcHVsYXRpb24uDQoNCk9mdGVuLCBjcmVhdGluZyBhIGNob3JvcGxldGggbWFwIHVzaW5nIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiBhIHZhcmlhYmxlIGNhbiBiZSBzb21ld2hhdCBtaXNsZWFkaW5nLiBBcyBzZWVuIGluIHRoZSBtYXAgYWJvdmUsIHRoZSB6b25lcyB3aXRoIHRoZSBsYXJnZXN0IHBvcHVsYXRpb24gYXJlIGFsc28gdXN1YWxseSBsYXJnZSB6b25lcy4gQW55IHByb2Nlc3MgdGhhdCB5b3UgbWlnaHQgdGhpbmsgb2Ygd2lsbCBiZSBjb25mb3VuZGVkIGJ5IHRoZSBzaXplIG9mIHRoZSB6b25lcy4gRm9yIHRoaXMgcmVhc29uLCBpdCBpcyBvZnRlbiBtb3JlIGluZm9ybWF0aXZlIHdoZW4gY3JlYXRpbmcgYSBjaG9yb3BsZXRoIG1hcCB0byB1c2UgYSB2YXJpYWJsZSB0aGF0IGlzIGEgcmF0ZSwgZm9yIGluc3RhbmNlIHBvcHVsYXRpb24gZGl2aWRlZCBieSBhcmVhIHRvIGdpdmUgcG9wdWxhdGlvbiBkZW5zaXR5Og0KYGBge3J9DQpwb3BfZGVuLm1hcCA8LSBnZ3Bsb3QoKSArIGdlb21fcG9seWdvbihkYXRhID0gSGFtaWx0b25fQ1QudCwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gY3V0X251bWJlcihQT1BVTEFUSU9OL0FSRUEsIDUpKSxjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAwLjEpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJZbE9yUmQiKSArDQogIGNvb3JkX2ZpeGVkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBsYWJzKGZpbGwgPSAiUG9wIERlbnNpdHkiKQ0KcG9wX2Rlbi5tYXANCmBgYA0KDQpJdCBjYW4gYmUgc2VlbiBub3cgdGhhdCB0aGUgcG9wdWxhdGlvbiBkZW5zaXR5IGlzIGhpZ2hlciBpbiB0aGUgbW9yZSBjZW50cmFsIHBhcnRzIG9mIEhhbWlsdG9uLCBCdXJsaW5ndG9uLCBEdW5kYXMsIGV0Yy4gRG9lcyB0aGUgbWFwIGxvb2sgcmFuZG9tPyBJZiBub3QsIHdoYXQgbWlnaHQgYmUgYW4gdW5kZXJseWluZyBwcm9jZXNzIHRoYXQgZXhwbGFpbnMgdGhlIHZhcmlhdGlvbnMgaW4gcG9wdWxhdGlvbiBkZW5zaXR5IGluIGEgY2l0eSBsaWtlIEhhbWlsdG9uPw0KDQpPdGhlciB0aW1lcywgaXQgaXMgYXBwcm9wcmlhdGUgdG8gc3RhbmRhcmRpemUgaW5zdGVhZCBvZiBieSBhcmVhLCBieSB3aGF0IG1pZ2h0IGJlIGNhbGxlZCB0aGUgX3BvcHVsYXRpb24gYXQgcmlza18uIEZvciBpbnN0YW5jZSwgbGV0cyBzYXkgdGhhdCB3ZSB3YW50ZWQgdG8gZXhwbG9yZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIG9mIG9sZGVyIGFkdWx0cyAoc2F5LCA2NSBhbmQgb2xkZXIpLiBJbiB0aGlzIGNhc2UsIG5vcm1hbGl6aW5nIG5vdCBieSBhcmVhLCBidXQgYnkgdGhlIHRvdGFsIHBvcHVsYXRpb24sIHdvdWxkIHJlbW92ZSB0aGUgInNpemUiIGVmZmVjdCwgZ2l2aW5nIGEgcHJvcG9ydGlvbjoNCmBgYHtyfQ0KZ2dwbG90KCkgKyBnZW9tX3BvbHlnb24oZGF0YSA9IEhhbWlsdG9uX0NULnQsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGN1dF9udW1iZXIoKEFHRV82NV9UT18gKyBBR0VfNzBfVE9fICsgQUdFXzc1X1RPXyArIEFHRV84MF9UT18gKyBBR0VfODUpL1BPUFVMQVRJT04sIDUpKSxjb2xvciA9IE5BLCBzaXplID0gMC4xKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiWWxPclJkIikgKw0KICBjb29yZF9maXhlZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgbGFicyhmaWxsID0gIlByb3AgQWdlIDY1KyIpDQpgYGANCg0KRG8geW91IG5vdGljZSBhIHBhdHRlcm4gaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBzZW5pb3JzIGluIHRoZSBIYW1pbHRvbiwgQ01BPw0KDQpUaGVyZSBhcmUgYSBmZXcgdGhpbmdzIHRvIGtlZXAgaW4gbWluZCB3aGVuIGNyZWF0aW5nIGNob3JvcGxldCBtYXBzLg0KDQpGaXJzdCwgd2hhdCBjbGFzc2lmaWNhdGlvbiBzY2hlbWUgdG8gdXNlLCB3aXRoIGhvdyBtYW55IGNsYXNzZXMsIGFuZCB3aGF0IGNvbG9ycz8gDQoNClRoZSBleGFtcGxlcyBhYm92ZSB3ZXJlIGFsbCBjcmVhdGVkIHVzaW5nIGEgY2xhc3NpZmljYXRpb24gc2NoZW1lIGJhc2VkIG9uIHRoZSBfcXVpbnRpbGVzXyBvZiB0aGUgZGlzdHJpYnV0aW9uLiBBcyBub3RlZCBhYm92ZSwgdGhlc2UgYXJlIG9idGFpbmVkIGJ5IGRpdmlkaW5nIHRoZSBzYW1wbGUgaW50byA1IGVxdWFsIHBhcnRzIHRvIGdpdmUgYm90dG9tIDIwJSwgZXRjLiwgb2Ygb2JzZXJ2YXRpb25zLiBUaGUgcXVpbnRpbGVzIGFyZSBhIHBhcnRpY3VsYXIgZm9ybSBvZiBhIHN0YXRpc3RpY2FsIG1lYXN1cmUga25vd24gYXMgX3F1YW50aWxlc18sIG9mIHdoaWNoIHRoZSBfbWVkaWFuXyBpcyB2YWx1ZSBvYnRhaW5lZCB3aGVuIHRoZSBzYW1wbGUgaXMgZGl2aWRlZCBpbiB0d28gZXF1YWwgc2l6ZWQgcGFydHMuIE90aGVyIGNsYXNzaWZpY2F0aW9uIHNjaGVtZXMgbWF5IGluY2x1ZGUgdGhlIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgYW5kIHNvIG9uLiANCg0KSW4gdGVybXMgb2YgaG93IG1hbnkgY2xhc3NlcyB0byB1c2UsIG9mdGVuIHRoZXJlIGlzIGxpdHRsZSBwb2ludCBpbiB1c2luZyBtb3JlIHRoYW4gc2l4IG9yIHNldmVuIGNsYXNzZXMsIGJlY2F1c2UgdGhlIGh1bWFuIGV5ZSBjYW5ub3QgZGlzdGluZ3Vpc2ggY29sb3IgZGlmZmVyZW5jZXMgYXQgYSBtdWNoIGhpZ2hlciByZXNvbHV0aW9uLg0KDQpUaGUgY29sb3JzIGFyZSBhIG1hdHRlciBvZiBzdHlsZSwgYnV0IHRoZXJlIGFyZSBjb2xvcmluZyBzY2hlbWVzIHRoYXQgYXJlIGNvbG9yYmxpbmQgc2FmZSAoc2VlIFtoZXJlXShodHRwOi8vY29sb3JicmV3ZXIyLm9yZy8jdHlwZT1zZXF1ZW50aWFsJnNjaGVtZT1CdUduJm49MykpLg0KDQpTZWNvbmRseSwgd2hlbiB0aGUgem9uaW5nIHN5c3RlbSBpcyBpcnJlZ3VsYXIgKGFzIG9wcG9zZWQgdG8sIHNheSwgYSByYXN0ZXIpLCBsYXJnZSB6b25lcyBjYW4gZWFzaWx5IGJlY29tZSBkb21pbmFudC4gSW4gZWZmZWN0LCBtdWNoIGRldGFpbCBpbiB0aGUgbWFwcyBhYm92ZSBpcyBsb3N0IGZvciBzbWFsbCB6b25lcywgd2hlcmVhcyBsYXJnZSB6b25lcywgZXNwZWNpYWxseSBpZiBzaW1pbGFybHkgY29sb3JlZCwgbWF5IG1pc2xlYWQgdGhlIGV5ZSBhcyB0byB0aGVpciByZWxhdGl2ZSBmcmVxdWVuY3kuDQoNCkFub3RoZXIgbWFwcGluZyB0ZWNobmlxdWUsIHRoZSBjYXJ0b2dyYW0sIGlzIG1lYW50IHRvIHJlZHVjZSB0aGUgaXNzdWVzIHdpdGggc21hbGwtbGFyZ2Ugem9uZXMuDQoNCiMgVmlzdWFsaXppbmcgYXJlYSBkYXRhOiBjYXJ0b2dyYW0NCg0KQSBjYXJ0b2dyYW0gaXMgYSBtYXAgd2hlcmUgdGhlIHNpemUgb2YgdGhlIHpvbmVzIGlzIGFkanVzdGVkIHNvIHRoYXQgaW5zdGVhZCBvZiBiZWluZyB0aGUgbGFuZCBhcmVhLCBpdCBpcyBwcm9wb3J0aW9uYWwgdG8gc29tZSBvdGhlciB2YXJpYWJsZSBvZiBpbnRlcmVzdC4NCg0KTGV0cyBpbGx1c3RyYXRlIHRoZSBpZGVhIGJlaGluZCB0aGUgY2FydG9ncmFtIGhlcmUuDQoNCkluIHRoZSBtYXBzIGFib3ZlLCB0aGUgem9uZXMgYXJlIGZhaXRoZnVsIHRvIHRoZWlyIGdlb2dyYXBoaWNhbCBwcm9wZXJ0aWVzLiBVbmZvcnR1bmF0ZWx5LCB0aGlzIG9ic2N1cmVkIHRoZSByZWxldmFuY2Ugb2Ygc21hbGwgem9uZXMuIEEgY2FydG9ncmFtIGNhbiBiZSB3ZWlnaHRlZCBieSBhbm90aGVyIHZhcmlhYmxlLCBzYXkgZm9yIGluc3RhbmNlLCB0aGUgcG9wdWxhdGlvbi4gSW4gdGhpcyB3YXksIHRoZSBzaXplIG9mIHRoZSB6b25lcyB3aWxsIGRlcGVuZCBvbiB0aGUgdG90YWwgcG9wdWxhdGlvbi4NCg0KQ2FydG9ncmFtcyBhcmUgaW1wbGVtZW50ZWQgaW4gUiBpbiB0aGUgcGFja2FnZSBgY2FydG9ncmFtYC4NCmBgYHtyfQ0KQ1RfcG9wX2NhcnRvZ3JhbSA8LSBjYXJ0b2dyYW0oc2hwID0gSGFtaWx0b25fQ1QsIHdlaWdodCA9ICJQT1BVTEFUSU9OIikNCmBgYA0KDQpOb3RpY2UgdGhhdCB0aGUgdmFsdWUgb2YgdGhlIGZ1bmN0aW9uIGBjYXJ0b2dyYW1gIChpLmUuLCBpdHMgb3V0cHV0KSBpcyBhIGBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWVgLiBUaGlzIG9iamVjdCBuZWVkcyB0byBiZSB0aWRpZWQgaWYgd2Ugd2lzaCB0byB1c2UgYGdncGxvdDJgIHRvIHZpc3VhbGl6ZSBpdDoNCmBgYHtyfQ0KQ1RfcG9wX2NhcnRvZ3JhbS50IDwtIHRpZHkoQ1RfcG9wX2NhcnRvZ3JhbSwgcmVnaW9uID0gIlRSQUNUIikNCkNUX3BvcF9jYXJ0b2dyYW0udCA8LSByZW5hbWUoQ1RfcG9wX2NhcnRvZ3JhbS50LCBUUkFDVCA9IGlkKQ0KYGBgDQoNCkFzIGJlZm9yZSwgdGhlIGRhdGEgd2VyZSBzdHJpcHBlZCBmcm9tIHRoZSB0aWRpZWQgdmVyc2lvbiBvZiB0aGUgZGF0YWZyYW1lLCBzbyB0aGV5IG5lZWQgdG8gYmUgcmVzdG9yZWQ6DQpgYGB7cn0NCkNUX3BvcF9jYXJ0b2dyYW0udCA8LSBsZWZ0X2pvaW4oQ1RfcG9wX2NhcnRvZ3JhbS50LCBDVF9wb3BfY2FydG9ncmFtQGRhdGEsIGJ5ID0gIlRSQUNUIikNCmBgYA0KDQoNClBsb3R0aW5nIHRoZSBjYXJ0b2dyYW06DQpgYGB7cn0NCmdncGxvdCgpICsgZ2VvbV9wb2x5Z29uKGRhdGEgPSBDVF9wb3BfY2FydG9ncmFtLnQsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGN1dF9udW1iZXIoUE9QVUxBVElPTiwgNSkpLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAwLjEpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJZbE9yUmQiKSArDQogIGNvb3JkX2ZpeGVkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBsYWJzKGZpbGwgPSAiUG9wdWxhdGlvbiIpDQpgYGANCg0KTm90aWNlIGhvdyB0aGUgc2l6ZSBvZiB0aGUgem9uZXMgaGFzIGJlZW4gYWRqdXN0ZWQuDQoNClRoZSBjYXJ0b2dyYW0gY2FuIGJlIGNvbWJpbmVkIHdpdGggY29sb3Jpbmcgc2NoZW1lcywgYXMgaW4gY2hvcm9wbGV0aCBtYXBzOg0KYGBge3J9DQpDVF9wb3BkZW5fY2FydG9ncmFtIDwtIGNhcnRvZ3JhbShIYW1pbHRvbl9DVCwgd2VpZ2h0ID0gIlBPUF9ERU5TSVQiKQ0KYGBgDQoNClRpZHkgYW5kIHJlc3RvcmUgdGhlIGRhdGE6DQpgYGB7cn0NCkNUX3BvcGRlbl9jYXJ0b2dyYW0udCA8LSB0aWR5KENUX3BvcGRlbl9jYXJ0b2dyYW0sIHJlZ2lvbiA9ICJUUkFDVCIpDQpDVF9wb3BkZW5fY2FydG9ncmFtLnQgPC0gcmVuYW1lKENUX3BvcGRlbl9jYXJ0b2dyYW0udCwgVFJBQ1QgPSBpZCkNCkNUX3BvcGRlbl9jYXJ0b2dyYW0udCA8LSBsZWZ0X2pvaW4oQ1RfcG9wZGVuX2NhcnRvZ3JhbS50LCBDVF9wb3BkZW5fY2FydG9ncmFtQGRhdGEsIGJ5ID0gIlRSQUNUIikNCmBgYA0KDQoNCg0KYGBge3J9DQpwb3BfZGVuLmNhcnRvZ3JhbSA8LSBnZ3Bsb3QoKSArIGdlb21fcG9seWdvbihkYXRhID0gQ1RfcG9wZGVuX2NhcnRvZ3JhbS50LCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBjdXRfbnVtYmVyKFBPUF9ERU5TSVQsIDUpKSxjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAwLjEpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJZbE9yUmQiKSArDQogIGNvb3JkX2ZpeGVkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBsYWJzKGZpbGwgPSAiUG9wIERlbnNpdHkiKQ0KcG9wX2Rlbi5jYXJ0b2dyYW0NCmBgYA0KDQpCeSBjb21iaW5pbmcgYSBjYXJ0b2dyYW0gd2l0aCBjaG9yb3BsZXRoIG1hcHBpbmcsIGl0IGJlY29tZXMgZWFzaWVyIHRvIGFwcHJlY2lhdGUgdGhlIHdheSBoaWdoIHBvcHVsYXRpb24gZGVuc2l0eSBpcyBjb25jZW50cmF0ZWQgaW4gdGhlIGNlbnRyYWwgcGFydHMgb2YgSGFtaWx0b24sIEJ1cmxpbmd0b24sIGV0Yy4NCmBgYHtyfQ0KZ3JpZC5hcnJhbmdlKHBvcF9kZW4ubWFwLCBwb3BfZGVuLmNhcnRvZ3JhbSwgbnJvdyA9IDEpDQpgYGANCg0KVGhpcyBjb25jbHVkZXMgUHJhY3RpY2UgOS4=